/*
 逍遥的心 2023年5月15日 于 成都 编写此代码
 本项目遵循MIT协议
*/
class Yue {
    constructor(){
		var that=this
        this.audioCtx = new AudioContext();
        this.isSing=false   //是否在播放
        this.iCycle=10      //每个音符占用时长，1为0.1秒，10即为1秒
        this.iCycleNow=0    //目前播放到一个音符单位的第几个位置
        this.iPLen =10      //音的放音时长
        this.freq  = 0     //播放哪个音调，默认第0个
        this.wavetype = 0
        this.playtype=0
        
        //音频接口对象定义
        //所有9个音阶的1~7频率库
        this.tonelib9=
        [
        //  C(do)     C#/Db     D(re)     D#/bE     E(mi)    F(fa)    F#/Gb    G(so)    G#/Ab    A(la)    A#/bB    B(si)
        //0
            16.352,  17.324,   18.354,   19.446,   20.602,  21.827,  23.125,  24.500,  25.957,  27.501,  29.136,  30.868,
        //1
            32.704,  34.649,   36.709,   38.892,   41.204,  43.655,  46.250,  49.001,  51.914,  55.001,  58.272,  61.737,
        //2
            65.408,   69.297,  73.418,   77.784,   82.409,  87.309,  92.501,  98.001, 103.829, 110.003, 116.544, 123.474,
        //3
           130.816,  138.595, 146.836,  155.567,  164.818, 174.618, 185.002, 196.002, 207.657, 220.005, 233.087, 246.947,
        //4
           261.632,  277.189, 293.672,  311.135,  329.636, 349.237, 370.003, 392.005, 415.315, 440.010, 466.175, 493.895,
        //5
           523.264,  554.379, 587.344,  622.269,  659.271, 698.473, 740.007, 784.010, 830.629, 880.021, 932.350, 987.790,
        //6
          1046.528, 1108.758,1174.688, 1244.538, 1318.542,1396.947,1480.013,1568.019,1661.258,1760.042,1864.699,1975.580,
        //7
          2093.056, 2217.515,2349.376,  2489.076, 2637.084, 2793.893,2960.027,3136.039,3322.517,3520.084,3729.398,3951.160,
        //8
          4186.112, 4435.031,4698.751, 4978.153, 5274.169,5587.787,5920.053,6272.077,6645.034,7040.168,7458.797,7902.319,
        //9
          8372.224, 8870.062,9397.502, 9956.306,10548.337,11175.573,11840.106,12544.155,13290.068,14080.335,14917.594,15804.639
        ];

        //乐谱中会用到的3阶1~7的频率对应
        this.tonelib3=
        [
        // 0   1    2     3   4    5    6    7    8    9    10   11
        // 1   1#   2    2#   3    4    4#   5    5#   6    6#   7
         262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494,
     
        // 12  13   14   15   16  17    18   19   20   21   22   23
        // 1   1#   2    2#   3    4    4#   5    5#   6    6#   7
         523, 544, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988,
     
     
        // 24   25  26   27   28   29   30   31   32   33   34   35
        // 1   1#   2    2#   3    4    4#   5    5#   6    6#   7
        1046,1109,1175,1245,1318,1397,1480,1568,1661,1760,1865,1976
        ];
        this.WAVE_TYPE=["sine","square","triangle","sawtooth"];
        this.PLAY_TYPE=["rand","stream"];
        this.tonenow=this.tonelib3
        this.yue_stream={lens:6,tone:[15,12,13,12,15,16],tonelen:[4,4,2,2,8,6],tonetype:[0,0,1,1,2,2]}
        this.yue_stream_i=0

        //产生并播放每个音符定时器
        this.SingTimer=setInterval(function(){
        	if(that.isSing==false)return
        	if(that.iCycleNow<that.iCycle){
        		that.iCycleNow++
        	}else{
        		that.iCycleNow=0
        		var i=that.PLAY_TYPE[that.playtype]
                switch(i){
                    case 'rand':
                        that.freq=Math.floor(Math.random()*that.tonenow.length)
                        break
                    case 'stream':
                        that.yue_stream_i++
                        if(that.yue_stream_i>=that.yue_stream.lens)that.yue_stream_i=0
                        that.freq=that.yue_stream.tone[that.yue_stream_i]
                        that.iPLen=that.yue_stream.tonelen[that.yue_stream_i]
                        that.wavetype=that.yue_stream.tonetype[that.yue_stream_i]
                        break
                    default:
                        break
                }
                that.Play()
        	}
        },100)
    }
    //播放函数Play
    Play() {
        var audioCtx=this.audioCtx
        var tonetype=this.tonenow
        var beat = this.iPLen
        var oscillator = audioCtx.createOscillator();
        var gainNode = audioCtx.createGain();
        oscillator.connect(gainNode);
        gainNode.connect(audioCtx.destination);
        oscillator.type = this.WAVE_TYPE[this.wavetype];
        oscillator.frequency.value = tonetype[this.freq];
        gainNode.gain.setValueAtTime(0, audioCtx.currentTime);
        gainNode.gain.linearRampToValueAtTime(1, audioCtx.currentTime + 0.01);
        oscillator.start(audioCtx.currentTime);
        gainNode.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + beat);
        oscillator.stop(audioCtx.currentTime + beat);
    }
    //播放随机音乐
    rand(){
	    this.iCycleNow=0
	    this.isSing=true
        this.playtype=0
    }
    sing(){
	    this.iCycleNow=0
	    this.isSing=true
        this.playtype=1
    }
    getMusic(yue){
        this.yue_stream=yue
    }
    //关闭
    shutup(){
	    this.isSing=false
    }
}